﻿/*  CLR版本: 4.0.30319.18063
 * 系统时间: 2014/10/31 14:20:43
 * 创建年份: 2014
 *     作者: 程炜.Snail
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Threading;
namespace Quick.Communicator
{
    /// <summary>
    /// 串口数据接收完成事件
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="e"></param>
    public delegate void SerialPortReceiveDataEndEventHandler(object obj, SerialPortEventArgs e);
    /// <summary>
    /// 信号发送完成 事件
    /// </summary>
    public delegate void SerialPortSendDataEndEventHandler(object sender, SendStateEventArgs e);
    /// <summary>
    /// 串口数据报文
    /// </summary>
    public class SerialPortEventArgs : EventArgs
    {
        private byte[] _DatagramByte;
        /// <summary>
        /// 客户端发送到服务器的报文
        /// 注意:在有些情况下报文可能只是报文的片断而不完整
        /// </summary>
        public byte[] DatagramByte
        {
            get { return _DatagramByte; }
            set { _DatagramByte = value; }
        }

        private string _Datagram;
        /// <summary>
        /// 客户端发送到服务器的报文
        /// 注意:在有些情况下报文可能只是报文的片断而不完整
        /// </summary>
        public string Datagram
        {
            get { return _Datagram; }
            set { _Datagram = value; }
        }
    }
    public class SuperSerialPort
    {
        #region 字段、属性
        private object LockObj = new object();
        /// <summary>
        /// 端口号
        /// </summary>
        public string PortName
        {
            get { return _SerialPort.PortName; }
            set { _SerialPort.PortName = value; }
        }
        /// <summary>
        /// 波特率
        /// </summary>
        public int BaudRate
        {
            get { return _SerialPort.BaudRate; }
            set { _SerialPort.BaudRate = value; }
        }
        /// <summary>
        /// 对象指定奇偶校验位
        /// </summary>
        public System.IO.Ports.Parity Parity
        {
            get { return _SerialPort.Parity; }
            set { _SerialPort.Parity = value; }
        }

        /// <summary>
        /// 每个字节的标准数据位长度
        /// </summary>
        public int DataBits
        {
            get { return _SerialPort.DataBits; }
            set { _SerialPort.DataBits = value; }
        }
        /// <summary>
        /// 使用的停止位
        /// </summary>
        public System.IO.Ports.StopBits StopBits
        {
            get { return _SerialPort.StopBits; }
            set { _SerialPort.StopBits = value; }
        }
        public bool DTR
        {
            get { return _SerialPort.DtrEnable; }
            set { _SerialPort.DtrEnable = value; }
        }
        public bool RTS
        {
            get { return _SerialPort.RtsEnable; }
            set { _SerialPort.RtsEnable = value; }
        }
        private IResolver _Resolver;
        /// <summary>
        /// 报文解析器
        /// </summary>
        public IResolver Resolver
        {
            get { return _Resolver; }
            set { _Resolver = value; }
        }
        /// <summary>
        /// 串口对象
        /// </summary>
        private SerialPort _SerialPort;
        ///// <summary>
        ///// 接收串口数据的线程
        ///// </summary>
        //private Thread _ReadByteThread;
        /// <summary>
        /// 剩下的会话报文
        /// </summary>
        private string _SpareDatagram;
        #endregion
        #region 事件
        /// <summary>
        /// 串口接收数据
        /// </summary>
        public event SerialPortReceiveDataEndEventHandler ReceiveDataEnd;

        public event SerialPortSendDataEndEventHandler SendDataEnd;
        #endregion
        public SuperSerialPort(SerialConfig config, IResolver resolver)
                            : this(config.PortName
                                 , config.BaudRate
                                 , config.Parity
                                 , config.DataBits
                                 , config.StopBits
                                 , resolver
                                 , config.DTR
                                 , config.RTS)
        { }
        public SuperSerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, IResolver resolver,bool DTR,bool RTS)
        {
            this._Resolver = resolver;
            _SerialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
            _SerialPort.DtrEnable = DTR;
            _SerialPort.RtsEnable = RTS;

            _SerialPort.DataReceived += SerialPort_DataReceived;
        }
        /// <summary>
        /// 是否运行
        /// </summary>
        public virtual bool IsRunning
        {
            get {
                return _SerialPort.IsOpen;
            }
        }
        /// <summary>
        /// 打开串口,进行接收数据
        /// </summary>
        public virtual void Start()
        {
            if (_SerialPort.IsOpen)
            {
                return;
            }
            try
            {
                _SerialPort.Open();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            //if (_SerialPort.IsOpen)
            //{
            //_ReadByteThread = new Thread(ReadByteDatagram);
            //_ReadByteThread.Start();
            //}
            //else
            if (!(_SerialPort?.IsOpen ?? false))
            {
                throw new Exception(string.Concat(_SerialPort.PortName, " 没有发现,或被其它设备占用!"));
            }
        }
        /// <summary>
        /// 关闭串口
        /// </summary>
        public virtual void Stop()
        {
            if (_SerialPort?.IsOpen ?? false)
            {
                try
                {
                    _SerialPort.Close();
                    //_ReadByteThread?.Abort();
                }
                catch (Exception e)
                { }
            }
        }
        public virtual void Dispose()
        {
            try
            {
                _SerialPort?.Dispose();
            }
            catch (Exception)
            {
                throw;
            }
        }
        public void SetParameter(SerialConfig config)
        {
            SetParameter(config.PortName,
                config.BaudRate,
                config.Parity,
                config.DataBits,
                config.StopBits,
                this._Resolver,
                config.DTR,
                config.RTS);
        }
        public void SetParameter(SerialConfig config, IResolver resolver)
        {
            SetParameter(config.PortName,
                config.BaudRate,
                config.Parity,
                config.DataBits,
                config.StopBits,
                resolver,
                config.DTR,
                config.RTS);
        }
        public void SetParameter(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, IResolver resolver, bool DTR, bool RTS)
        {
            bool isRun = IsRunning;
            Stop();
            _SerialPort.PortName = portName;
            _SerialPort.BaudRate = baudRate;
            _SerialPort.Parity = parity;
            _SerialPort.DataBits = dataBits;
            _SerialPort.StopBits = stopBits;
            _SerialPort.DtrEnable = DTR;
            _SerialPort.RtsEnable = RTS;
            this._Resolver = resolver;
            if (isRun)
            {
                Start();
            }
        }
        /// <summary>
        /// 串口接收到数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                List<byte> byteReadList = new List<byte>();
                byte[] bytesData = null;

                int bytesRead = _SerialPort.BytesToRead;

                while (bytesRead > 0)
                {
                    byte[] byData = new byte[bytesRead];
                    _SerialPort.Read(byData, 0, bytesRead);
                    byteReadList.AddRange(byData);
                    Thread.Sleep(5);
                    bytesRead = _SerialPort.BytesToRead;
                }
                lock (LockObj)
                {
                    bytesData = byteReadList.ToArray();
                    if (null != ReceiveDataEnd)
                    {
                        if (string.IsNullOrEmpty(_Resolver.EndTag) || string.IsNullOrEmpty(_Resolver.HexStringEndTag)) // 如果没有报文结束符标记,则直接进行数据转发
                        {
                            SerialPortEventArgs spe = new SerialPortEventArgs();
                            spe.DatagramByte = bytesData;
                            spe.Datagram = this._Resolver.DatagramDesEncoding(bytesData);
                            //发布一个报文消息
                            OnReceiveDataEnd(_SerialPort, spe);
                        }
                        else //存在报文结束符,则需要进行分割
                        {
                            string receivedData = this._Resolver.ByteToHexString(bytesData);

                            if (!string.IsNullOrEmpty(this._SpareDatagram))
                            {
                                //加上最后一次通讯剩余的报文片断
                                receivedData = string.Concat(this._SpareDatagram, ",", receivedData);
                            }
                            string[] recvDatagrams = _Resolver.Resolve(ref receivedData);
                            //剩余的代码片断,下次接收的时候使用
                            this._SpareDatagram = receivedData;
                            receivedData = null;
                            foreach (string newDatagram in recvDatagrams)
                            {
                                SerialPortEventArgs spe = new SerialPortEventArgs();
                                spe.DatagramByte = this._Resolver.HexStringToByte(newDatagram);
                                spe.Datagram = this._Resolver.DatagramDesEncoding(spe.DatagramByte);
                                //发布一个报文消息
                                OnReceiveDataEnd(_SerialPort, spe);
                            }
                        }
                    }
                }
            }
            catch
            { }
        }
        /// <summary>
        /// 触发数据接收完成的事件
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="e"></param>
        private void OnReceiveDataEnd(object sender, SerialPortEventArgs e)
        {
            if (null != ReceiveDataEnd)
            {
                Delegate[] delegateList = ReceiveDataEnd.GetInvocationList();
                foreach (SerialPortReceiveDataEndEventHandler handler in delegateList)
                {
                    handler.BeginInvoke(sender, e, null, null);
                }            
            }
        }
        private void OnSendDataEnd(object sender, SendStateEventArgs e)
        {
            if (null != SendDataEnd)
            {
                Delegate[] delegateList = SendDataEnd.GetInvocationList();
                foreach (SerialPortSendDataEndEventHandler handler in delegateList)
                {
                    handler.BeginInvoke(sender, e, null, null);
                }
            }
        }
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="isAddEndTag"></param>
        /// <returns></returns>
        public bool SendData(string msg, bool isAddEndTag = true)
        {
            if (null == _SerialPort || !_SerialPort.IsOpen)
            {
                return false;
            }
            byte[] bt = this._Resolver.DatagramEncodingBarringEngTag(msg);
            return SendData(bt, isAddEndTag);
        }
        /// <summary>
        /// 发送16进制字符串给设备
        /// </summary>
        /// <param name="data"></param>
        /// <param name="isAddEndTag"></param>
        /// <returns></returns>
        public bool SendHexStringData(string data, bool isAddEndTag = true)
        {
            byte[] bt = this._Resolver.HexStringToByte(data);
            return SendData(bt, isAddEndTag);
        }
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="isAddEndTag"></param>
        /// <returns></returns>
        public bool SendData(byte[] bt, bool isAddEndTag = true)
        {
            try
            {
                if (null == _SerialPort || !_SerialPort.IsOpen)
                {
                    return false;
                }
                if (isAddEndTag)
                {
                    bt = this._Resolver.DatagramAddEndTag(bt);
                }
                _SerialPort.Write(bt, 0, bt.Length);
                OnSendDataEnd(_SerialPort, new SendStateEventArgs(SendState.Success));
                return true;
            }
            catch (Exception)
            {
                OnSendDataEnd(_SerialPort, new SendStateEventArgs(SendState.Failure));
                return false;
            }
        }
    }
}
